package assets {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getDefinitionByName;

	/**
	 * @author Charlie MacIsaac
	 * Loads, queues and stores Asset's.  Use load() to initate a load and getClass to access
	 * linked files
	 */
	
	public class AssetManager extends EventDispatcher {
		// PROPERTIES =============================================================================
		private var _assetLoaders : Array;
		private var _assets : Array;
		private var _loadQueue : Array;
		
		private var _loaderInProgess : AssetLoader;
		private var _loadedCount : uint;
		
		// GETTERS + SETTERS ======================================================================
		public function get progress() : Number {
			var totalToLoad : uint = _loadedCount + _loadQueue.length;
			var loadProgress : Number;
			if (_loaderInProgess) {
				totalToLoad++;
				loadProgress = _loadedCount / totalToLoad + (_loaderInProgess.percentLoaded / totalToLoad);
			} else {
				loadProgress = _loadedCount / totalToLoad;
			}
			return loadProgress;
		}
		
		// CONSTRUCTOR ============================================================================
		public function AssetManager() {
			_assets = new Array();
			_assetLoaders = new Array();
			_loadQueue = new Array();
		}
		
		// PUBLIC =================================================================================
		/**
		 * Queues the parameter object for loading and dispatches a Event.COMPLETE when finished.
		 * @param	toLoad	An array of Asset's or a single Asset.
		 */
		public function load(toLoad : Object) : void {
			if (toLoad is Asset) {
				queueAsset(Asset(toLoad));
			} else if (toLoad is Array) {
				for each (var asset : Asset in toLoad) {
					queueAsset(asset);
				}
			}
			
			if (!_loaderInProgess) loadNext();
		}
		
		/**
		 * Returns a Class definition of an object if it has been loaded.
		 * @param	name	The linkage / class name
		 * @return	null if the object isn't loaded.
		 */
		public function getClass(name : String) : Class {
			try {
				return getDefinitionByName(name) as Class;
			} catch (e : Error) {
				trace("[AssetManager.getClass] |WARN| Class :" + name + ": was not found.");
			}
			return null;
		}
		
		// PRIVATE ================================================================================
		private function queueAsset(asset : Asset) : void {
			var assetLoader : AssetLoader = new AssetLoader(asset, loadComplete);
			_assets.push(asset);
			_loadQueue.push(assetLoader);
		}
		
		private function loadNext() : void {
			var next : AssetLoader = AssetLoader(_loadQueue.shift());
			_loaderInProgess = next;
			next.load();
		}
		
		// LISTENERS ==============================================================================
		private function loadComplete() : void {
			_loaderInProgess = null;
			_loadedCount++;
			
			if (_loadQueue.length) {
				loadNext();
			}
			else {
				dispatchEvent(new Event(Event.COMPLETE));
				_loadedCount = 0;
			}
		}
	}
}